#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/timeb.h>
#include <time.h>
#include "debug.h"

static int logfd = -1;                           	/** 日志文件描述符 */
static debug_level_em debug_level = LOG_WARNING;    /** 日志文件级别，默认warning */
static int s_enable_dpkt = 0;    						/** 是否允许打印数据包内容 */


static const char *error_strs[] = {
	"[Off]",
	"[Error]",
	"[Warning]",
	"[Info]",
	"[Debug]",
	"[TRACE]"
};

//设置日志文件及日志过滤级别
//如果传入filename，则日志写入文件
void debug_level_set(char *filename, debug_level_em level, int enable_dpkt)
{
    debug_level = level;

    if (logfd > 0) {
        close(logfd);
        logfd = -1;
    }

    if ((filename != NULL) && (strlen(filename) > 0)) {
        logfd = open(filename, O_CREAT|O_WRONLY|O_APPEND, 0777);
        if (logfd < 0) {
            debug_level = LOG_OFF;
            printf("filename:%s, logfile is NULL, turn off debug log output\n", filename);
        }
    }

    s_enable_dpkt = enable_dpkt;
}

void debug_output_simple(debug_level_em type, const char *fmt, ...)
{
	if (type > debug_level)
		return;

	if (!fmt)
		return;

	char msg[MAX_DEBUG_MSG_SIZE];

	va_list ap;
	va_start(ap, fmt);
	vsnprintf(msg, MAX_DEBUG_MSG_SIZE, fmt, ap);
	va_end(ap);

	if (logfd < 0) {
		printf("%s", msg);
	} else {
		write(logfd, msg, strlen(msg));
	}
	return ;
}

void debug_output_pkt(const char *fmt, ...)
{
	if (!s_enable_dpkt) {
		return ;
	}

	if (!fmt)
		return;

	char msg[MAX_DEBUG_MSG_SIZE];

	va_list ap;
	va_start(ap, fmt);
	vsnprintf(msg, MAX_DEBUG_MSG_SIZE, fmt, ap);
	va_end(ap);

	if (logfd < 0) {
		printf("%s", msg);
	} else {
		write(logfd, msg, strlen(msg));
	}
	return ;
}

//日志调试接口
void debug_output(debug_level_em type, const char *file, const char *func, int lineno, const char *fmt, ...)
{
	if (debug_level == 0 || type > debug_level)
		return;

	if (!fmt)
		return;

	char msg[MAX_DEBUG_MSG_SIZE];
	snprintf(msg, MAX_DEBUG_MSG_SIZE, "%s[pid:%d][%s:%s:%d]>>>> ", error_strs[type], getpid(), file, func, lineno);
	int idx = strlen(msg);

	va_list ap;
	va_start(ap, fmt);
	vsnprintf(&msg[idx], MAX_DEBUG_MSG_SIZE - idx, fmt, ap);
	va_end(ap);

	if (logfd < 0) {
		printf("%s", msg);
	} else {
		write(logfd, msg, strlen(msg));
	}
	return ;
}


#define PKT_PRINT       printf
//hexdump打印
void pr_hexdump(const char* p, int len)
{
    if (!s_enable_dpkt) {
        return ;
    }

    const char* line;
    int i;
    int thisline;
    int offset;

    line = p;
    offset = 0;
    PKT_PRINT("\n");
    while (offset < len) {
        PKT_PRINT("%04x ", offset);
        thisline = len - offset;
        if (thisline > 16) {
            thisline = 16;
        }
        for (i = 0; i < thisline; i++) {
            if (i == 8) {
                PKT_PRINT(" ");
            }

            PKT_PRINT("%02x ", (unsigned char)line[i]);
        }
        for (; i < 16; i++) {
            PKT_PRINT("   ");
        }
        for (i = 0; i < thisline; i++) {
            if (i == 8) {
                PKT_PRINT(" ");
            }

            PKT_PRINT("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
        }
        PKT_PRINT("\n");
        offset += thisline;
        line += thisline;
    }
    PKT_PRINT("\n");
}

// 打印请求包
void client_pkt_dump(char *buf, int len)
{
    PKT_PRINT("\nclient->server  byte[0x%x]:", len);
    pr_hexdump(buf, len);
    PKT_PRINT("\n");
}

// 打印响应包
void server_pkt_dump(char *buf, int len)
{
    PKT_PRINT("\nserver->client  byte[0x%x]:", len);
    pr_hexdump(buf, len);
    PKT_PRINT("\n");
}